
`include "common_header.verilog"

//  *************************************************************************
//  File : crc32gen64.v
//  *************************************************************************
//  This program is controlled by a written license agreement.
//  Unauthorized reproduction or use is expressly prohibited.
//  Copyright (c) 2014 MorethanIP
//  Muenchner Strasse 199, 85757 Karlsfeld, Germany
//  info@morethanip.com
//  http://www.morethanip.com
//  *************************************************************************
//  Designed by : Muhammad Anisur Rahman, Thomas Schrobenhauser
//  info@morethanip.com
//  *************************************************************************
//  Description : CRC32 generator with 64-bit input and 1 cycle latency
//  Version     : $Id: crc32gen64.v,v 1.1 2014/04/15 12:06:14 ts Exp $
//  *************************************************************************

module crc32gen64 (
   reset,
   clk,
   clk_ena,
   sof,
   eof,
   data,
   dmod,
   crc_vld,
   crc
   );

input   reset;
input   clk;
input   clk_ena;
input   sof;                    //  first word
input   eof;                    //  last word
input   [63:0] data;            //  data input
input   [2:0] dmod;             //  last word modulo information
output  crc_vld;                //  CRC value is valid
output  [31:0] crc;             //  CRC value

reg     crc_vld;
wire    [31:0] crc;

reg     frame_on;               //  in frame
wire    [31:0] crc8;            //  crc for 8-bit of input
wire    [31:0] crc16;           //  crc for 16-bit of input
wire    [31:0] crc24;           //  crc for 24-bit of input
wire    [31:0] crc32;           //  crc for 32-bit of input
wire    [31:0] crc40;           //  crc for 40-bit of input
wire    [31:0] crc48;           //  crc for 48-bit of input
wire    [31:0] crc56;           //  crc for 56-bit of input
wire    [31:0] crc64;           //  crc for 64-bit of input
reg     [31:0] reg_out;         //  crc register
reg     [31:0] crc_r;
wire    [31:0] crc_intz;        //  final crc zeroes appended


//  Lower 32-bit
//  ------------
crc32galstep8c U_C8 (

   .data( data[7:0] ),
   .crc_in( reg_out ),
   .crc_out( crc8 ) );

crc32galstep16c U_C16 (

   .data( data[15:0] ),
   .crc_in( reg_out ),
   .crc_out( crc16 ) );

crc32galstep24c U_C24 (

   .data( data[23:0] ),
   .crc_in( reg_out ),
   .crc_out( crc24 ) );

crc32galstep32c U_C32 (

   .data( data[31:0] ),
   .crc_in( reg_out ),
   .crc_out( crc32 ) );


//  Upper 32-bit
//  ------------
crc32galstep8c U_C40 (

   .data( data[39:32] ),
   .crc_in( crc32 ),
   .crc_out( crc40 ) );

crc32galstep16c U_C48 (

   .data( data[47:32] ),
   .crc_in( crc32 ),
   .crc_out( crc48 ) );

crc32galstep24c U_C56 (

   .data( data[55:32] ),
   .crc_in( crc32 ),
   .crc_out( crc56 ) );

crc32galstep32c U_C64 (

   .data( data[63:32] ),
   .crc_in( crc32 ),
   .crc_out( crc64 ) );


//  Frame marker
//  ------------
always @(posedge clk or posedge reset)
   begin : process_1
   if (reset == 1'b 1)
      begin
      frame_on <= 1'b 0;
      end
   else
      begin
      if (clk_ena == 1'b 1)
         begin
         if (sof == 1'b 1 & eof == 1'b 0)
            begin
            frame_on <= 1'b 1;
            end
         else if (eof == 1'b 1 )
            begin
            frame_on <= 1'b 0;
            end
         end
      end
   end


//  Galois multiplier loop (with 1 preset)
//  --------------------------------------
always @(posedge clk or posedge reset)
   begin : process_2
   if (reset == 1'b 1)
      begin
      reg_out <= {32{1'b 0}};
      end
   else
      begin
      if (clk_ena == 1'b 1)
         begin
         if (sof == 1'b 0 & frame_on == 1'b 0)
            begin
            reg_out <= 32'b 10010010001001101111010101100010;   //  galois preset will be FF after 32 shifts
            end
         else
            begin
            reg_out <= crc64;   //  only full words are cycled
            end
         end
      end
   end


//  Provide result
//  --------------
always @(posedge clk or posedge reset)
   begin : process_3
   if (reset == 1'b 1)
      begin
      crc_vld <= 1'b 0;
      crc_r   <= 32'h 00000000;
      end
   else
      begin
      if (clk_ena == 1'b 1)
         begin
         if (frame_on == 1'b 1 & eof == 1'b 1)
            begin
            crc_vld <= 1'b 1;
            end
         else
            begin
            crc_vld <= 1'b 0;
            end

         //  check which stage to use for the final result

         if (frame_on == 1'b 1)   //  keep running until eof, then save last value
            begin
            case (dmod)
                3'b 000: crc_r <= crc64;
                3'b 001: crc_r <= crc8;
                3'b 010: crc_r <= crc16;
                3'b 011: crc_r <= crc24;
                3'b 100: crc_r <= crc32;
                3'b 101: crc_r <= crc40;
                3'b 110: crc_r <= crc48;
                default: crc_r <= crc56;
            endcase
            end
         end
      end
   end

// append 32 zero bits to galois field result

crc32zero32c U_CZERO (

   .crc_in( crc_r ),
   .crc_out( crc_intz ) );

assign crc = ~crc_intz;


endmodule // module crc32gen64
